const app = require('j7/app');
const utils = require('j7/utils');
const log = require('j7/log');

const metaClassList = [];
const metaClasses = {};
const web3ConfHash = {};
let web3ServiceConf = null;
let configDir = './config/';

function registerMetaClass(fileName, primKey, wrapClass) {
  const metaClass = {
    'fileName' : fileName,
    'primKey' : primKey,
    'wrapClassName': wrapClass,
    'wrapClass': require('./' + wrapClass),
    'rawList' : [],
    'rawHash' : {},
    'wrapList' : [],
    'wrapHash' : {},
  };
  metaClassList.push(metaClass);
  metaClasses[wrapClass] = metaClass;
}

function load() {
  metaClassList.forEach((metaClass) => {
    const json = utils.readJsonFromFile(metaClass['fileName']);
    if (!json) {
      throw new Error('读取配置' + metaClass['fileName'] + '失败');
    }
    if (Array.isArray(json)) {
      metaClass['rawList'] = json;

    } else {
      metaClass['rawList'].push(json);
    }
    let idx = 0;
    metaClass['rawList'].forEach(function (item) {
      const wrapOjb = new metaClass['wrapClass'](item, metaClass);
      const wrapProxy = new Proxy(wrapOjb, wrapOjb._getHandler());
      metaClass['wrapList'].push(wrapProxy);
      if (metaClass['primKey'] == '') {
        metaClass['rawHash'][idx] = item;
        metaClass['wrapHash'][idx] = wrapProxy;
      } else {
        metaClass['rawHash'][item[metaClass['primKey']]] = item;
        metaClass['wrapHash'][item[metaClass['primKey']]] = wrapProxy;
      }
      ++idx;
    });
    //log.debug(utils.jsonEncode(metaClass));
  });
  {
    for (let i = 0; i < 3; ++i) {
      metaClassList.forEach((metaClass) => {
        metaClass['wrapList'].forEach((item) => {
          if (item['_init' + i]) {
            item['_init' + i](exports);
          }
        });
      });
    }
    metaClassList.forEach((metaClass) => {
      metaClass['wrapList'].forEach((item) => {
        item.lock();
      });
    });
    traverseMetaList('Web3WebHooks', (item, idx) => {
      if (item['instance_id'] == app.getInstanceId()) {
        web3ServiceConf = item;
      }
    });
  }
}

async function init() {
  configDir = './config/';
  if (utils.isOnlineEnv()) {
    configDir = '../config/';
  } else if (utils.getArgv('env') == 'dev'){
    configDir = './config_dev/';
  }
  console.log(configDir, utils.getArgv('env'));

  let resDir = './res/';
  if (utils.isOnlineEnv()) {
    resDir = '../res/';
  } else if (utils.getArgv('env') == 'dev'){
    resDir = './res_dev/';
  }
  console.log(resDir);

  registerMetaClass(configDir + 'config.json',
                    '',
                    'Config'
                   );
  registerMetaClass(configDir + 'bcevent_mysql.json',
                    '',
                    'BcEventDb'
                   );
  registerMetaClass(configDir + 'web3webhooks.cluster.json',
                    '',
                    'Web3WebHooks'
                   );
  load();
  {
    traverseMetaList('BcEventDb', (dbConf, idx) => {
      app.registerDb('BcEventDb' + idx, dbConf);
    });
  }
}

function getMetaClass(name) {
  return utils.hasKey(metaClasses, name) ? metaClasses[name] : null;
}

function getMetaByKey(name, key) {
  const metaClass = getMetaClass(name);
  return metaClass && key in metaClass['wrapHash'] ? metaClass['wrapHash'][key] : null;
}

function getMetaList(name) {
  const metaClass = getMetaClass(name);
  return metaClass ? metaClass['wrapList'] : null;
}

function callMetaStatic(name, method, ...args) {
  const metaClass = getMetaClass(name);
  return metaClass['wrapClass'][method](...args);
}

function traverseMetaList(name, cb) {
  const metaList = getMetaList(name);
  if (metaList) {
    for (let i = 0; i < metaList.length; ++i) {
      if (!cb(metaList[i], i, metaList.length)) {
        break;
      }
    }
  }
}

function getWeb3WebHooksConf() {
  return web3ServiceConf;
}

exports.init = init;

exports.getMetaByKey = getMetaByKey;
exports.traverseMetaList = traverseMetaList;
exports.callMetaStatic = callMetaStatic;

exports.getWeb3WebHooksConf = getWeb3WebHooksConf;
